// Mouse.cpp: implementation of the Mouse class.
//
//////////////////////////////////////////////////////////////////////

#include "Mouse.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Mouse::Mouse()
{
this->oldPosition[MOUSE_X] = 0;
this->oldPosition[MOUSE_Y] = 0;

this->deltaPosition[MOUSE_X] = 0;
this->deltaPosition[MOUSE_Y] = 0;

this->direction = 0x0;
}

Mouse::~Mouse()
{

}

void Mouse::locatePointer(int x, int y)
{
	// clean up the one hot buffer for direction
	this->direction = 0x0;

	//fprintf ( stderr, "Mouse is at (%4dx%4d)\r", x, y ) ;

	this->deltaPosition[MOUSE_X] = x - this->oldPosition[MOUSE_X];
	this->deltaPosition[MOUSE_Y] = y - this->oldPosition[MOUSE_Y];

	// what was the movement detected?
	if(this->deltaPosition[MOUSE_X] > 0)
		{
		this->direction |= MOUSE_RIGHT;
		}
	else if(this->deltaPosition[MOUSE_X] < 0)
		{
		this->direction |= MOUSE_LEFT;
		}
	else 
	    {
        this->direction &= ~(MOUSE_RIGHT | MOUSE_LEFT);
        }

	if(this->deltaPosition[MOUSE_Y] < 0)
		{
		this->direction |= MOUSE_UP;
		}
	else if(this->deltaPosition[MOUSE_Y] > 0)
		{
		this->direction |= MOUSE_DOWN;
		}
	else 
	    {
        this->direction &= ~(MOUSE_UP | MOUSE_DOWN);
        }
        
	// the current position becomes the old one
	this->oldPosition[MOUSE_X] = x;
	this->oldPosition[MOUSE_Y] = y;
}

void Mouse::readButtons(int button, int updn, int x, int y)
{
this->locatePointer(x,y);
  if (button == PW_LEFT_BUTTON)
  {
     if(updn == PW_DOWN) { this->buttons |= MOUSE_BUTTON_LEFT; } else { this->buttons &= ~(MOUSE_BUTTON_LEFT);}
  }
  else if(button == PW_RIGHT_BUTTON)
  {
     if(updn == PW_DOWN) { this->buttons |= MOUSE_BUTTON_RIGHT; } else { this->buttons &= ~(MOUSE_BUTTON_RIGHT);}
  }
  else if(button == PW_MIDDLE_BUTTON)
  {
     if(updn == PW_DOWN) { this->buttons |= MOUSE_BUTTON_CENTER; } else { this->buttons &= ~(MOUSE_BUTTON_CENTER);}
  }
  //fprintf ( stderr, "Mouse button %d dirn %d at (%4dx%4d)\n", button, updn, x, y ) ;
}

int Mouse::isDirection(int direction)
{
	if(direction & this->direction)
		{
		if( (direction == MOUSE_RIGHT) || (direction == MOUSE_LEFT) )
			{
			return this->deltaPosition[MOUSE_X];
			}
		else
			{
			return -this->deltaPosition[MOUSE_Y];
			}
		}
	else
		{
		return 0;
		}
}

int Mouse::isWorking()
{
	// Mouse supposed to work always... 
	return 1;
}

void Mouse::clear()
{
this->deltaPosition[MOUSE_X] = 0;
this->deltaPosition[MOUSE_Y] = 0;
}

int Mouse::isPressed(int button)
{
    if(button & this->buttons)
        {
        return 1;
        }
    else
        {
        return 0;
        }
}

sgdLineSegment3* Mouse::unproject(int x, int y, Camera *c)
{
GLint viewport[4];
GLdouble projmatrix[16],mvmatrix[16];
GLint realy;  /*  OpenGL y coordinate position  */
GLdouble wx, wy, wz;  /*  returned world x, y, z coords  */
GLdouble wxw, wyw, wzw;

/* Load the OpenGL matrices (biewport and projection are correct, modelview is Ones) */
glGetIntegerv (GL_VIEWPORT, viewport);
glGetDoublev (GL_PROJECTION_MATRIX, projmatrix);
glGetDoublev (GL_MODELVIEW_MATRIX, mvmatrix);

// Get the current context
ssgContext *curr_context = ssgGetCurrentContext();

/* Set Near-Far... */
/* Get normal plane */ 
/*sgVec3 far_clip_plane_normal;
sgSetVec3(far_clip_plane_normal,c->getCameraPosition()->xyz[SG_X],c->getCameraPosition()->xyz[SG_Y],c->getCameraPosition()->xyz[SG_Z]);
sgNormaliseVec3(far_clip_plane_normal);
printf("Clip plane normal : [%f %f %f]\n", far_clip_plane_normal[SG_X],far_clip_plane_normal[SG_Y],far_clip_plane_normal[SG_Z]);

sgVec3 origin;
sgSetVec3(origin,0.0f,0.0f,0.0f);

sgVec4 far_clip_plane;
sgMakePlane(far_clip_plane,far_clip_plane_normal,origin);

curr_context->setClipPlane(5,far_clip_plane);//*/

/* Create a support sgMat4 for MODELVIEW */
sgMat4 modelview;
curr_context->getModelviewMatrix(modelview);

/* This matrix should be of doubles!!! */
sgdMat4 d_modelview;
makeSgMat4double(modelview,d_modelview);
//printSgMat4(modelview);

/* Create a support matrix for PROJECTION */
sgMat4 projection;
curr_context->getProjectionMatrix(projection);

//printSgMat4(projection);

/* This matrix shoul be of doubles!!! */
sgdMat4 d_projection;
makeSgMat4double(projection,d_projection);

/*  note viewport[3] is height of window in pixels  */
realy = viewport[3] - (GLint) y - 1;

gluUnProject ((GLdouble) x, (GLdouble) realy, 0.0, (GLdouble *) d_modelview, (GLdouble *)d_projection, viewport, &wx, &wy, &wz); 
gluUnProject ((GLdouble) x, (GLdouble) realy, 1.0, (GLdouble *) d_modelview, (GLdouble *)d_projection, viewport, &wxw, &wyw, &wzw); 

// Create the sgVec3* line (used to SSG_ISECT!!!)
sgdLineSegment3 *lineS = (sgdLineSegment3*)malloc(sizeof(sgdLineSegment3));
sgdSetVec3(lineS->a,wxw, wyw, wzw);
sgdSetVec3(lineS->b,wx, wy, wz);

curr_context->setNearFar(CAMERA_NEAR,CAMERA_FAR);

return lineS;
}